﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Threading;
using System.IO;

using Factonomy.AzureUtility.Core;
using Factonomy.AzureUtility.Core.StorageHelpers;
using Factonomy.AzureUtility.Core.Storage;

namespace Factonomy.AzureUtility.Controls
{
    /// <summary>
    /// Interaction logic for AzureTreeView.xaml
    /// </summary>
    public partial class AzureTreeView : UserControl
    {
        public event NoParameterDelegate LoadComplete;
        public event NoParameterDelegate RenderComplete;
        //public event NoParameterDelegate BlobAdded;
        public event TreeViewItemHelperDelegate AccountItemClicked;
        public event TreeViewItemHelperDelegate ContainersItemClicked;
        public event TreeViewItemHelperDelegate ContainerItemClicked;

        private XmlDocument _doc = new XmlDocument();
        private AccountsContextMenu _accountsContextMenu = new AccountsContextMenu();
        private AccountContextMenu _accountContextMenu = new AccountContextMenu();
        private ContainersContextMenu _containersContextMenu = new ContainersContextMenu();
        private ContainerContextMenu _containerContextMenu = new ContainerContextMenu();
        private TablesContextMenu _tablesContextMenu = new TablesContextMenu();
        private TableContextMenu _tableContextMenu = new TableContextMenu();

        protected virtual void OnLoadComplete()
        {
            if (LoadComplete != null)
                LoadComplete();
        }

        protected virtual void OnRenderComplete()
        {
            if (RenderComplete != null)
                RenderComplete();
        }

        //protected virtual void OnBlobAdded()
        //{
        //    if (BlobAdded != null)
        //        BlobAdded();
        //}

        protected virtual void OnAccountItemClicked(TreeViewItemHelper helper)
        {
            if (AccountItemClicked != null)
                AccountItemClicked(helper);
        }

        protected virtual void OnContainersItemClicked(TreeViewItemHelper helper)
        {
            if (ContainersItemClicked != null)
                ContainersItemClicked(helper);
        }

        protected virtual void OnContainerItemClicked(TreeViewItemHelper helper)
        {
            if (ContainerItemClicked != null)
                ContainerItemClicked(helper);
        }

        public AzureTreeView()
        {
            InitializeComponent();

            this._accountsContextMenu.AccountAdded += new NoParameterDelegate(OnContextMenuAccountAdded);

            this._accountContextMenu.AccountRemoved += new NoParameterDelegate(OnAccountContextMenuAccountRemoved);
            this._accountContextMenu.AccountAdded += new NoParameterDelegate(OnContextMenuAccountAdded);

            this._containersContextMenu.ContainerAdded += new TreeViewItemHelperDelegate(OnContainersContextMenuContainerAdded);

            BlobHelper.Instance.ContainerDeleted += new BlobContainerDelegate(OnContainerContextMenuContainerDeleted);

            //this._containerContextMenu.ContainerDeleted += new TreeViewItemHelperDelegate(OnContainerContextMenuContainerDeleted);
            this.uiTreeView.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(uiTreeView_SelectedItemChanged);

            //this._containerContextMenu.BlobAdded += new NoParameterDelegate(OnBlobAdded);

            this.Clear();
        }

        void OnContextMenuAccountAdded()
        {
            this.Init();
        }

        public void Clear()
        {
            //this.uiHeader.Text = string.Empty;
            //this.uiSubHeader.Text = string.Empty;
        }

        void OnAccountContextMenuAccountRemoved()
        {
            this.RemoveSelectedItem();
        }

        public TreeViewItemHelper GetSelectedHelper()
        {
            if (this.uiTreeView.SelectedItem != null)
            {
                TreeViewItem item = this.uiTreeView.SelectedItem as TreeViewItem;
                if (item.Tag != null)
                {
                    return item.Tag as TreeViewItemHelper;
                }
            }

            return null;
        }

        private void OnContainerContextMenuContainerDeleted(BlobContainer sender)
        {
            this.DeleteContainer(sender.AccountName, sender.ContainerName);
            this.ReRender();
            this.SelectNode(sender.AccountName, this.uiTreeView.Items);
        }

        private void uiTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            TreeView treeView = sender as TreeView;
            if (treeView.SelectedItem == null)
            {
            }
            else
            {
                TreeViewItem item = treeView.SelectedItem as TreeViewItem;
                if (item.Tag != null)
                {
                    TreeViewItemHelper helper = item.Tag as TreeViewItemHelper;
                    switch (helper.NodeType)
                    {
                        case TreeViewItemHelper.NodeTypeEnum.Account:
                            this.ShowAccountDetails(helper);
                            this.OnAccountItemClicked(helper);
                            break;
                        case TreeViewItemHelper.NodeTypeEnum.Containers:
                            this.ShowAccountDetails(helper); 
                            this.OnAccountItemClicked(helper);
                            this.OnContainersItemClicked(helper);
                            break;
                        case TreeViewItemHelper.NodeTypeEnum.Container:
                            this.ShowAccountDetails(helper); 
                            this.OnAccountItemClicked(helper);
                            this.OnContainerItemClicked(helper);
                            break;
                    }
                }
            }
        }

        private void ShowAccountDetails(TreeViewItemHelper helper)
        {
            //IconBitmapDecoder decoder = new IconBitmapDecoder(ResourceManager.GetSquareIcon, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None);
            //uiHeaderIcon.Source = decoder.Frames[0];
            //this.uiHeader.Text = helper.AccountName;
            //this.uiSubHeader.Text = this._blobHelper.GetBaseUri(Config.Instance.GetAccount(helper.AccountName)).ToString();
        }

        private void OnContainersContextMenuContainerAdded(TreeViewItemHelper sender)
        {
            this.AddContainer(sender.AccountName, sender.Container);
            this.ReRender();
            this.SelectNode(sender.Container, this.uiTreeView.Items);
        }

        private void SelectNode(string header, ItemCollection items)
        {
            foreach (TreeViewItem item in items)
            {
                if (item.Header.ToString() == header)
                {
                    item.IsSelected = true;
                    break;
                }

                this.SelectNode(header, item.Items);
            }
        }

        public void Init()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<root>");

            foreach (ConfigAccount account in Config.Instance.ListAccounts())
            {
                sb.Append("<account>");
                sb.Append("<name><![CDATA[" + this.GetNewTreeNodeName() + "]]></name>");
                sb.Append("<id><![CDATA[" + account.AccountName + "]]></id>");
                sb.Append("<sharedkey><![CDATA[" + account.SharedKey + "]]></sharedkey>");
                sb.Append("<local><![CDATA[" + account.Local.ToString() + "]]></local>");
                sb.Append("<enabled><![CDATA[" + account.Enabled.ToString() + "]]></enabled>");

                bool valid = account.Enabled;

                if (valid)
                {
                    valid = BlobHelper.Instance.Test(account);
                }

                sb.Append("<valid><![CDATA[" + valid.ToString() + "]]></valid>");

                sb.Append("<containers>");
                sb.Append("<name><![CDATA[" + this.GetNewTreeNodeName() + "]]></name>");

                if (valid)
                {
                    foreach (BlobContainer blobContainer in BlobHelper.Instance.ListContainers(account))
                    {
                        sb.Append("<container>");
                        sb.Append("<name><![CDATA[" + this.GetNewTreeNodeName() + "]]></name>");
                        sb.Append("<id><![CDATA[" + blobContainer.ContainerName + "]]></id>");
                        sb.Append("<uri><![CDATA[" + blobContainer.ContainerUri + "]]></uri>");
                        sb.Append("<baseuri><![CDATA[" + blobContainer.BaseUri + "]]></baseuri>");
                        sb.Append("</container>");
                    }
                }
                sb.Append("</containers>");

                sb.Append("<tables>");
                sb.Append("<name><![CDATA[" + this.GetNewTreeNodeName() + "]]></name>");

                if (valid)
                {
                    foreach (string table in TableHelper.Instance.ListTables(account))
                    {
                        sb.Append("<table>");
                        sb.Append("<name><![CDATA[" + this.GetNewTreeNodeName() + "]]></name>");
                        sb.Append("<id><![CDATA[" + table + "]]></id>");
                        sb.Append("</table>");
                    }
                }

                sb.Append("</tables>");


                sb.Append("</account>");
            }

            sb.Append("</root>");

            this._doc.LoadXml(sb.ToString());

            this.OnLoadComplete();
        }

        private string GetNewTreeNodeName()
        {
            return "ui" + Guid.NewGuid().ToString().Replace("-", "").ToLower();
        }

        public void AddContainer(string accountName, string containerName)
        {
            XmlNode node = this._doc.SelectSingleNode("root/account[id='" + accountName + "']/containers");
            if (node != null)
            {
                BlobContainer container = BlobHelper.Instance.GetContainer(Config.Instance.GetAccount(accountName), containerName);
                XmlDocument doc = new XmlDocument();
                StringBuilder sb = new StringBuilder();
                sb.Append("<container>");
                sb.Append("<name><![CDATA[" + this.GetNewTreeNodeName() + "]]></name>");
                sb.Append("<id><![CDATA[" + container.ContainerName + "]]></id>");
                sb.Append("<uri><![CDATA[" + container.ContainerUri + "]]></uri>");
                sb.Append("<baseuri><![CDATA[" + container.BaseUri + "]]></baseuri>");
                sb.Append("<expanded><![CDATA[True]]></expanded>");
                sb.Append("</container>");
                doc.LoadXml(sb.ToString());
                node.AppendChild(this._doc.ImportNode(doc.DocumentElement, true));
            }
        }

        public void DeleteContainer(string accountName, string containerName)
        {
            XmlNode node = this._doc.SelectSingleNode("root/account[id='" + accountName + "']/containers/container[id='" + containerName + "']");
            if (node != null)
            {
                node.ParentNode.RemoveChild(node);
            }
        }

        public void Render()
        {
            if (this.uiTreeView.Dispatcher.CheckAccess())
            {
                this.uiTreeView.Items.Clear();

                TreeViewItem accountsItem = new TreeViewItem();
                accountsItem.Header = "Accounts";
                accountsItem.IsExpanded = true;
                accountsItem.ContextMenu = this._accountsContextMenu;

                foreach (XmlNode node in this._doc.DocumentElement.ChildNodes)
                {
                    ConfigAccount account = Config.Instance.GetAccount(node["id"].InnerText);
                    TreeViewItem item = new TreeViewItem();
                    item.Name = node["name"].InnerText;
                    item.Header = node["id"].InnerText;
                    this.AddItemHelper(item, account, TreeViewItemHelper.NodeTypeEnum.Account, string.Empty);
                    item.ContextMenu = this._accountContextMenu;
                    //item.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(TreeItemClick);

                    //if (node["enabled"].InnerText.ToLower() == "false")
                    //{
                    //    item.Foreground = Brushes.Red;
                    //}

                    if (node["containers"] != null)
                    {
                        TreeViewItem containersItem = new TreeViewItem();
                        containersItem.Name = node["containers"]["name"].InnerText;
                        containersItem.Header = "Blob Containers";
                        this.AddItemHelper(containersItem, account, TreeViewItemHelper.NodeTypeEnum.Containers, string.Empty);
                        containersItem.ContextMenu = this._containersContextMenu;
                        //containersItem.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(TreeItemClick);

                        foreach (XmlNode containers in node["containers"].SelectNodes("container"))
                        {
                            TreeViewItem containerItem = new TreeViewItem();
                            containerItem.Name = containers["name"].InnerText;
                            containerItem.Header = containers["id"].InnerText;
                            this.AddItemHelper(containerItem, account, TreeViewItemHelper.NodeTypeEnum.Container, containers["id"].InnerText);
                            containerItem.ContextMenu = this._containerContextMenu;
                            //containerItem.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(TreeItemClick); 
                            containersItem.Items.Add(containerItem);
                        }

                        item.Items.Add(containersItem);
                    }

                    if (node["tables"] != null)
                    {
                        TreeViewItem tablesItem = new TreeViewItem();
                        tablesItem.Name = node["tables"]["name"].InnerText;
                        tablesItem.Header = "Tables";
                        tablesItem.ContextMenu = this._tablesContextMenu;
                        this.AddItemHelper(tablesItem, account, TreeViewItemHelper.NodeTypeEnum.Tables, string.Empty);

                        foreach (XmlNode table in node["tables"].SelectNodes("table"))
                        {
                            TreeViewItem tableItem = new TreeViewItem();
                            tableItem.Name = table["name"].InnerText;
                            tableItem.Header = table["id"].InnerText;
                            tablesItem.Items.Add(tableItem);
                            tableItem.ContextMenu = this._tableContextMenu;
                            this.AddItemHelper(tableItem, account, TreeViewItemHelper.NodeTypeEnum.Table, table["id"].InnerText);
                        }

                        item.Items.Add(tablesItem);
                    }

                    accountsItem.Items.Add(item);
                }

                this.uiTreeView.Items.Add(accountsItem);

                this.OnRenderComplete();
            }
            else
            {
                this.uiTreeView.Dispatcher.Invoke(DispatcherPriority.Normal, new NoParameterDelegate(this.Render));
            }
        }

        public void ReRender()
        {
            List<string> list = new List<string>();
            this.FindOpenNodes(this.uiTreeView.Items, ref list);
            this.Render();
            this.OpenNodes(this.uiTreeView.Items, list);
        }

        private void FindOpenNodes(ItemCollection items, ref List<string> list)
        {
            foreach (TreeViewItem item in items)
            {
                if (item.IsExpanded)
                {
                    list.Add(item.Name);
                }

                this.FindOpenNodes(item.Items, ref list);
            }
        }

        private void OpenNodes(ItemCollection items, List<string> openNodes)
        {
            foreach (string name in openNodes)
            {
                foreach (TreeViewItem item in items)
                {
                    if (item.Name == name)
                    {
                        item.IsExpanded = true;
                        break;
                    }

                    this.OpenNodes(item.Items, openNodes);
                }
            }
        }

        void TreeItemClick(object sender, MouseButtonEventArgs e)
        {
            TreeViewItem item = sender as TreeViewItem;
            if (item.Tag != null)
            {
                TreeViewItemHelper helper = item.Tag as TreeViewItemHelper;
                switch (helper.NodeType)
                {
                    case TreeViewItemHelper.NodeTypeEnum.Account:
                        this.OnAccountItemClicked(helper);
                        break;
                    case TreeViewItemHelper.NodeTypeEnum.Containers:
                        this.OnContainersItemClicked(helper);
                        break;
                    case TreeViewItemHelper.NodeTypeEnum.Container:
                        this.OnContainerItemClicked(helper);
                        break;
                }
            }
        }

        private void AddItemHelper(TreeViewItem item, ConfigAccount account, TreeViewItemHelper.NodeTypeEnum nodeType, string container)
        {
            TreeViewItemHelper helper = new TreeViewItemHelper();
            helper.AccountName = account.AccountName;
            helper.NodeType = nodeType;
            helper.Container = container;
            item.Tag = helper;
        }

        private string GetAccount(TreeViewItem parent)
        {
            while (parent != null)
            {
                if (parent.Parent.GetType() == typeof(TreeView))
                {
                    return parent.Header.ToString();
                }
                parent = parent.Parent as TreeViewItem;
            }

            return string.Empty;
        }

        public void RemoveSelectedItem()
        {
            if (this.uiTreeView.SelectedItem != null)
            {
                ((TreeViewItem)((TreeViewItem)this.uiTreeView.SelectedItem).Parent).Items.Remove(this.uiTreeView.SelectedItem);
            }
        }
    }
}
